/**
 * 单个扫描结果弹窗
 */

import React from 'react';
import PropTypes from 'prop-types';
import { Dialog, Tag, Button, Balloon } from '@teamix/ui';
import exceed from 'utils/apimap';
import ListLoading from 'atComponents/ListLoading';
import File from 'components/buildResultIssues/file';
import UsersAvatar from '@alife/teamix-at-users-avatar';
import utils from 'utils';
import sha1 from 'sha1';
import MarkdownIt from 'markdown-it';
import MarkdownItReplaceLink from 'markdown-it-replace-link';
import { filterXSS } from 'xss';
import './index.scss';
import intl from '../../../locale';

const prefix = 'pinpoint-single-build-detail';

const md = new MarkdownIt({
  html: true,
  linkify: true,
}).use(MarkdownItReplaceLink);

const { organization } = window.FORCE;
const levelMap = {
  Blocker: 'red',
  Major: 'blue',
  Critical: 'orange',
};

// 问题出现位置的key
const breakAt = 'breakAt';
const dialogId = 'pippoint-build-detail-dialog';

export default class buildDetailDialog extends React.Component {
  static propTypes = {
    // build数据
    build: PropTypes.object,
    // 当前issue
    issue: PropTypes.object,
    onClose: PropTypes.func,
    projectId: PropTypes.number,
    updateCommitId: PropTypes.func,
  };

  static defaultProps = {
    build: {},
    issue: {},
    onClose: () => {},
    projectId: window.FORCE.pathResource ? window.FORCE.pathResource.id : null,
    closeCommitDetail: () => {},
    updateCommitId: () => {},
  };

  constructor(props) {
    super(props);
    this.dialog = React.createRef();
    this.state = {
      activityList: [],
      isLoadingActivity: true,
      issue: props.issue,
      isNeedRefreshTable: false,
      // 激活的选项
      activeInfo: {
        index: 'breakAt',
      },
      issue_list: [],
    };
  }

  componentDidMount() {
    this.getActivity();
    this.getIssuesDetail();
  }

  // 改变状态，更新数据
  updateInfo = (issue) => {
    this.setState({
      issue,
      // 更新了状态，需要关闭时更新所有表格数据
      isNeedRefreshTable: true,
    });

    this.getActivity();
  };

  onClose = () => {
    const { onClose, refreshData } = this.props;
    const { isNeedRefreshTable } = this.state;
    onClose && onClose();
    isNeedRefreshTable && refreshData && refreshData();
  };

  // 获取操作记录
  getActivity = () => {
    const { build } = this.props;
    const { issue } = this.state;
    exceed
      .fetch({
        api: 'projects.builds.single.activity',
        params: {
          org_id: organization.id,
        },

        data: {
          build_id: build.id,
          issue_id: issue.build_issue_id,
          issue_type: 'pinpoint',
        },
      })
      .then((result) => {
        const list = result.slice(1);
        this.setState({
          isLoadingActivity: false,
          activityList: list,
        });
      })
      .fail((err) => {
        console.error(err);
        this.setState({
          isLoadingActivity: false,
        });
      });
  };

  forceUpdateDialog = () => {
    // 供子元素异步加载后强制更新dialog，否则会导致不出滚动条
    // 现在样式修改后，无需更新即可出滚动条，待删除
  };

  renderCommitId = (commitId) => {
    if (!commitId) {
      return null;
    }
    return (
      <Button
        type="primary"
        text
        style={{ margin: '0 4px', flexShrink: 0 }}
        onClick={(e) => {
          this.props.onClose();
          this.props.updateCommitId(e, commitId);
        }}
      >
        {commitId.slice(0, 8)}
      </Button>
    );
  };

  renderActivityItem = (item) => {
    const operationType = item.operation_type ? item.operation_type.toLowerCase() : '';
    const { commit_id, reason } = item.extra_info ? item.extra_info : {};
    let text = '';
    switch (operationType) {
      case 'created':
        text = intl.get({
          id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.ScanToFindProblems',
          defaultMessage: '扫描发现问题',
        });
        break;
      case 'resolved':
      case 'fixed':
        text = (
          <span className="detail">
            <span>{item.operator_name}</span>
            {intl.get({
              id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.Submitted',
              defaultMessage: '提交',
            })}
            {this.renderCommitId(commit_id)}
            {intl.get({
              id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.FixedTheIssue',
              defaultMessage: '修复了问题',
            })}
          </span>
        );

        break;
      case 'unresolved':
      case 'new':
        text = (
          <span className="detail">
            <span>{item.operator_name}</span>
            {intl.get({
              id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.Submitted',
              defaultMessage: '提交',
            })}
            {this.renderCommitId(commit_id)}
            {intl.get({
              id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.TheCurrentIssueIsNot',
              defaultMessage: '未解决当前问题',
            })}
          </span>
        );

        break;
      case 'ignore':
      case 'ignored': {
        text = (
          <span className="detail">
            <span>{item.operator_name}</span>
            {intl.get({
              id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.IgnoredProblem',
              defaultMessage: '忽略了问题',
            })}
            {reason
              ? intl.get(
                  {
                    id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.ReasonForClosingReason',
                    defaultMessage: '，关闭原因：{reason}',
                  },
                  { reason },
                )
              : ''}
          </span>
        );
        break;
      }
      case 'open':
      case 'reopened':
        text = (
          <span className="detail">
            <span>{item.operator_name}</span>
            {intl.get({
              id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.TheProblemIsReopenedAnd',
              defaultMessage: '重新打开了问题，扫描结果问题未解决',
            })}
          </span>
        );

        break;
      case 'close':
        text = (
          <span className="detail">
            <span>{item.operator_name}</span>
            {intl.get({
              id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.TheProblemWasManuallyClosed',
              defaultMessage: '手动关闭了问题，关闭原因：',
            })}
            {reason}
          </span>
        );

        break;
      default:
        text = '';
    }

    return (
      <div className={`${prefix}-history-list-item`}>
        <div className={`${prefix}-history-list-item-left`}>{text}</div>
        <div className={`${prefix}-history-list-item-right`}>
          {utils.getBeautyTime(item.gmt_create)}
        </div>
      </div>
    );
  };

  // 先按文件分类，然后获取文件对应的行号
  getAllFiles = ({ steps, file, issue }) => {
    const breakAtFile = file.file_name;
    const allFiles = [];
    steps.forEach((f) => {
      const hasFile = allFiles.some((item) => {
        return item.file_name === f.filepath;
      });
      if (!hasFile) {
        allFiles.push({
          file_name: f.filepath,
          issue_count_info: { blocker: 0, critical: 0, major: 0, ...{ [issue.level]: 1 } },
          issue_id_list: [issue.build_issue_id],
          build_result_id: issue.build_result_id,
          no_issue: f.filepath !== breakAtFile,
        });
      }
    });
    return allFiles;
  };

  // 点击切换文件或者行号
  changeActiveKey = (item) => {
    this.setState({
      activeInfo: item,
    });

    try {
      const scrollEle = document.querySelector(`#${dialogId} .next-dialog-body`);
      const targetLine = document.querySelector(
        `#${dialogId} .next-dialog-body #file_${sha1(
          item.filepath,
        )} .blob-line-num[data-number=line${item.begin_line}]`,
      );

      const scrollTop =
        targetLine.offsetParent.offsetParent.offsetTop +
        targetLine.offsetParent.offsetTop +
        targetLine.offsetTop;
      scrollEle.scrollTop = scrollTop;
    } catch (e) {
      console.error(e);
    }
  };

  // 转化成通用格式
  commonFile = () => {
    const { issue } = this.props;
    // 转化成通用格式
    const file = {
      file_name: issue.file_name,
      issue_count_info: { blocker: 0, critical: 0, major: 0, ...{ [issue.level]: 1 } },
      issue_id_list: [issue.build_issue_id],
      build_result_id: issue.build_result_id,
    };
    return file;
  };

  getIssuesDetail() {
    const { projectId } = this.props;
    const file = this.commonFile();

    const { issue_id_list } = file;

    const buildId = file.build_result_id;

    exceed
      .fetch({
        api: 'projects.builds.issues.batch',
        params: { projectId: projectId || window.FORCE.pathResource.id, buildId },
        data: {
          issue_ids: issue_id_list.join(','),
        },
      })
      .then((result) => {
        result.shift();

        this.setState({
          issue_list: result,
        });
      })
      .fail(console.log);
  }

  getCreateCommitId = (activityList) => {
    // 获取引入的记录
    const createdActivity = activityList.find(
      (item) => item.operation_type && item.operation_type.toLowerCase() === 'created',
    );
    let createCommitId =
      (createdActivity && createdActivity.extra_info && createdActivity.extra_info.commit_id) || '';

    if (!createCommitId) {
      createCommitId = this.state.issue_list[0] ? this.state.issue_list[0].intro_commit : '';
    }
    return createCommitId;
  };

  render() {
    const { build, projectId } = this.props;
    const { isLoadingActivity, activityList, issue, activeInfo } = this.state;
    // 转化成通用格式
    const file = {
      file_name: issue.file_name,
      issue_count_info: { blocker: 0, critical: 0, major: 0, ...{ [issue.level]: 1 } },
      issue_id_list: [issue.build_issue_id],
      build_result_id: issue.build_result_id,
    };

    const createCommitId = this.getCreateCommitId(activityList);

    const evidence = issue.evidence ? JSON.parse(issue.evidence) : [];
    // 接口返回自带所有步骤，而前端如果拼接的话，就需要去除最后一个。
    evidence.pop();
    // 额外的文件issue嵌入内容
    const extraIssueList = evidence.map((item) => {
      return {
        begin_line: item.begin_line,
        level: `${item.index}`,
        title: item.message,
        file_name: item.filepath,
        no_desc: true,
      };
    });
    // 右侧步骤
    const steps = [
      ...evidence,
      {
        index: breakAt,
        message: intl.get({
          id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.ProblemLocation',
          defaultMessage: '问题出现位置',
        }),
        filepath: issue.file_name,
        begin_line: issue.begin_line,
      },
    ];

    const allFiles = this.getAllFiles({ steps, file, issue });

    return (
      <React.Fragment>
        <Dialog
          title={<div>{issue.title}</div>}
          visible
          style={{ width: 1000, minHeight: '224px', overflowY: 'hidden' }}
          className={`${prefix}-dialog`}
          onCancel={this.onClose}
          onClose={this.onClose}
          footer={false}
          isFullScreen
          id={dialogId}
          ref={this.dialog}
        >
          <div>
            {isLoadingActivity ? (
              <ListLoading />
            ) : (
              <div className={prefix} key={this.state.dialogKey}>
                <div className={`${prefix}-top`}>
                  <div className={`${prefix}-top-left`}>
                    <div className={`${prefix}-title`}>
                      {intl.get({
                        id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.BasicInformation',
                        defaultMessage: '基础信息',
                      })}
                    </div>
                    <div className={`${prefix}-info`}>
                      <div className={`info-user ${prefix}-info-item`}>
                        <div className={`${prefix}-info-item-left`}>
                          {intl.get({
                            id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.Introduced',
                            defaultMessage: '引入人',
                          })}
                        </div>
                        <div className={`${prefix}-info-item-right`} style={{ paddingLeft: 5 }}>
                          <UsersAvatar
                            dataSource={[
                              {
                                id: '',
                                name: issue.owner,
                                avatarUrl: issue.avatar || '',
                              },
                            ]}
                            size="xs"
                            borderColor={'#f7f7f7'}
                          />

                          <span style={{ marginLeft: 8 }}>{issue.owner}</span>
                        </div>
                      </div>
                      <div className={`info-state ${prefix}-info-item`}>
                        <div className={`${prefix}-info-item-left`}>
                          {intl.get({
                            id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.ProblemLevel',
                            defaultMessage: '问题等级',
                          })}
                        </div>
                        <div className={`${prefix}-info-item-right`} style={{ marginRight: -4 }}>
                          <Tag color={levelMap[issue.level] || undefined}>{issue.level}</Tag>
                        </div>
                      </div>
                      <div className={`info-version ${prefix}-info-item`}>
                        <div className={`${prefix}-info-item-left`}>
                          {intl.get({
                            id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.ImportAndSubmit',
                            defaultMessage: '引入提交',
                          })}
                        </div>
                        <div className={`${prefix}-info-item-right`}>
                          <span style={{ marginRight: 8 }}>{build.branch}</span>
                          {this.renderCommitId(createCommitId)}
                        </div>
                      </div>
                    </div>
                  </div>
                  <div className={`${prefix}-top-right`}>
                    <div className={`${prefix}-title`}>
                      {intl.get({
                        id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.IssueDynamics',
                        defaultMessage: '问题动态',
                      })}
                    </div>
                    <div className={`${prefix}-history`}>
                      <div className={`${prefix}-history-list`}>
                        {activityList.map((item) => {
                          return this.renderActivityItem(item);
                        })}
                      </div>
                    </div>
                  </div>
                </div>
                <div className={`${prefix}-bottom`}>
                  <div className={`${prefix}-file`}>
                    {allFiles.map((f) => {
                      return (
                        <div id={`file_${sha1(f.file_name)}`}>
                          <File
                            file={f}
                            showIssuesInFile
                            build={build}
                            commitId={createCommitId}
                            projectId={projectId}
                            isInProjectSecurity
                            noIssue={f.no_issue}
                            forceUpdateDialog={this.forceUpdateDialog}
                            activeLine={
                              activeInfo.filepath === f.file_name ? activeInfo.begin_line : ''
                            }
                            extraIssueList={extraIssueList.filter(
                              (item) => item.file_name === f.file_name,
                            )}
                          />
                        </div>
                      );
                    })}
                  </div>
                  <div className={`${prefix}-issues`}>
                    <div className={`${prefix}-issues-title`}>
                      {intl.get({
                        id: 'code-assets.pinpointBuildIssuesList.issueDetailDialog.ProblemPath',
                        defaultMessage: '问题路径',
                      })}
                    </div>
                    <div>
                      {steps.map((item) => {
                        return (
                          <div
                            className={`${prefix}-overview-item ${
                              activeInfo.index === item.index ? 'active' : ''
                            }`}
                            onClick={() => {
                              this.changeActiveKey(item);
                            }}
                          >
                            <div className="dot" />
                            <Balloon.Tooltip
                              align="t"
                              trigger={
                                <div
                                  className="overview-content one-line-ellipsis markdown-body"
                                  dangerouslySetInnerHTML={{
                                    __html: filterXSS(
                                      md.render(
                                        `${item.index !== breakAt ? `${item.index}.` : ''}${
                                          item.message
                                        }`,
                                      ),
                                    ),
                                  }}
                                />
                              }
                            >
                              <div
                                className="markdown-body"
                                dangerouslySetInnerHTML={{
                                  __html: filterXSS(
                                    md.render(
                                      `${item.index !== breakAt ? `${item.index}.` : ''}${
                                        item.message
                                      }`,
                                    ),
                                  ),
                                }}
                              />
                            </Balloon.Tooltip>
                          </div>
                        );
                      })}
                    </div>
                  </div>
                </div>
              </div>
            )}
          </div>
        </Dialog>
      </React.Fragment>
    );
  }
}
